import { _decorator, color, Component, Label, Node, Sprite } from 'cc';
const { ccclass, property } = _decorator;

type MapType = Array<Array<{
    x: number,
    y: number,
    /**是否是障碍物 */
    isWall: boolean,
    /**从起点到该节点的实际代价 */
    g: number, // 
    /**从该节点到终点的估计代价（启发式） */
    h: number, // 
    /**总代价 f = g + h */
    f: number, // 
    /**父节点，路径重构时使用 */
    parent: MapType[0][0] | null,
    /**临时方向 */
    tDir?:'left'|'right'|'top'|'bottom'|'leftTop'|'rightTop'|'leftBottom'|'rightBottom',
    /**临时障碍物 */
    isWallTemp?:boolean
}>>;

type dirType = 'four' | 'eight';

@ccclass('scene')
export class scene extends Component {

    startNode: MapType[0][0] = null;
    endNode: MapType[0][0] = null;

    isClick = false;
    isPath = false;


    private _dirType: dirType = 'four';
    public get dirType(): dirType {
        return this._dirType;
    }
    public set dirType(v:dirType) {
        this._dirType = v;
    }
    /**卡位 */
    cardSlot=true;


    start() {
        this.initMap();

        this.node.getChildByName('box').children.forEach((el, index) => {
            el.on(Node.EventType.TOUCH_END, () => {
                if (el.name === 'wall') return;
                if (this.isClick) return;

                if (this.isPath) {
                    this.node.getChildByName('box').children.forEach((el) => {
                        if (el.name !== 'wall') el.getComponent(Sprite).color = color().fromHEX('#ffffff');
                    });
                    this.isPath = false;
                }

                let node = this.map[Math.floor(index / 12)][index % 12];
                if (!this.startNode) {
                    this.startNode = node;
                    el.getComponent(Sprite).color = color().fromHEX('#00ff00');
                    return;
                }

                if (!this.endNode) {
                    this.endNode = node;
                    el.getComponent(Sprite).color = color().fromHEX('#0000ff');
                };
                this.isClick = true;
                let path = this.aStar(this.map, this.startNode, this.endNode,this.dirType);

                this.renderPath(path);
            })
        });

        this.node.getChildByName('dirBtn').on(Node.EventType.TOUCH_END, () => {
            this.dirType = this.dirType == 'four' ? 'eight' : 'four';
            let txtEl = this.node.getChildByName('dirBtn').getChildByName('Label').getComponent(Label);
            txtEl.string = this.dirType == 'four' ? '四方向' : '八方向';
        });
        this.node.getChildByName('cardSlotBtn').on(Node.EventType.TOUCH_END, () => {
            this.cardSlot=!this.cardSlot;

            let txtEl = this.node.getChildByName('cardSlotBtn').getChildByName('Label').getComponent(Label);
            txtEl.string = this.cardSlot ? '卡位' : '不卡位';
        });

        
    }

    /**地图 */
    map: MapType = [];

    /**创建地图 */
    initMap() {
        this.node.getChildByName('box').children.forEach((el, index) => {
            let line = Math.floor(index / 12);

            if (!this.map[line]) {
                this.map[line] = [];
            };
            this.map[line].push({
                x: index % 12,
                y: line,
                isWall: el.name === 'wall',
                g: 0,
                h: 0,
                f: 0,
                parent: null,
                tDir:null
            });

        });

    }

    /**启发函数--计算距离 */
    heuristic(a: MapType[0][0], b: MapType[0][0]) {
        // 曼哈顿距离
        return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
    }

    /**
     * 获取邻居节点 四方向
     */
    getNeighbors(grid: MapType, node: MapType[0][0]) {
        let neighbors: Array<MapType[0][0]> = [];

        let { x, y } = node;
        let numRows = grid.length;
        let numCols = grid[0].length;

        //左 右  上 下
        if (x > 0) {
            if(grid[y][x - 1])grid[y][x - 1].tDir='left';

            neighbors.push(grid[y][x - 1]);
        }
        if (x < numCols - 1) {
            
            if(grid[y][x + 1])grid[y][x + 1].tDir='right';

            neighbors.push(grid[y][x + 1]);
        }
        if (y > 0) {
            
            if(grid[y - 1][x])grid[y-1][x].tDir='top';

            neighbors.push(grid[y - 1][x]);
        }
        if (y < numRows - 1) {

            if(grid[y + 1][x])grid[y+1][x].tDir='bottom';

            neighbors.push(grid[y + 1][x]);
        }


        return neighbors;

    }

    /**
     * 获取邻居节点 八方向
     */
    getNeighborsEight(grid: MapType, node: MapType[0][0]) {
        grid.forEach((item)=>{
            item.forEach(el=>{
                el.isWallTemp=false;
            })
        })
        
        let neighbors: Array<MapType[0][0]> = [];

        let { x, y } = node;
        let numRows = grid.length;
        let numCols = grid[0].length;

        neighbors.push(...this.getNeighbors(grid, node))

        //左上、右上、左下、右下
        if (x > 0 && y > 0) {
            grid[y - 1][x - 1].tDir='leftTop';
            neighbors.push(grid[y - 1][x - 1]);
        }
        if (x < numCols - 1 && y > 0) {
            grid[y - 1][x + 1].tDir='rightTop';
            neighbors.push(grid[y - 1][x + 1]);
        }
        if (x > 0 && y < numRows - 1) {
            grid[y + 1][x - 1].tDir='leftBottom';
            neighbors.push(grid[y + 1][x - 1]);
        }
        if (x < numCols - 1 && y < numRows - 1) {
            grid[y + 1][x + 1].tDir='rightBottom';
            neighbors.push(grid[y + 1][x + 1]);
        }

        //判断是不是卡位
        let left,right,top,bottom;
        neighbors.forEach((item,i)=>{
            switch (item.tDir) {
                case 'left':
                    left={...item,i}
                break;
                case 'right':
                    right={...item,i}
                break;
                case 'top':
                    top={...item,i}
                break;
                case 'bottom':
                    bottom={...item,i}
                break;
            }
        });

        let setWall=(dir)=>{
            neighbors.forEach((item)=>{
                if(item.tDir == dir){
                    item.isWallTemp=true;
                }
            });
        }

        if(this.cardSlot){
            if(left?.isWall && top?.isWall){ setWall('leftTop') }
            if(left?.isWall && bottom?.isWall){ setWall('leftBottom') }
            if(right?.isWall && top?.isWall){ setWall('rightTop') }
            if(right?.isWall && bottom?.isWall){ setWall('rightBottom') }
        }

        
        


        return neighbors;
    }


    /**
     * A*算法
     * @param grid 地图
     * @param start 开始节点
     * @param end 结束节点
     * @param dir 方向
     */
    aStar(grid: MapType, start: MapType[0][0], end: MapType[0][0], dir = 'four') {
        grid = JSON.parse(JSON.stringify(grid));
        /**打开列表，存放待处理节点 */
        let openList: Array<MapType[0][0]> = [];
        /**关闭列表，存放已处理节点 */
        let closedList: Array<MapType[0][0]> = [];

        openList.push(start);

        while (openList.length > 0) {
            // 找到具有最小 f 值的节点
            let lowestIndex = 0;
            for (let i = 1; i < openList.length; i++) {
                if (openList[i].f < openList[lowestIndex].f) {
                    lowestIndex = i;
                }
            }

            // 当前节点
            let currentNode = openList[lowestIndex];

            // 如果当前节点是终点，构建并返回路径
            if (currentNode.x === end.x && currentNode.y === end.y) {
                let path = [];
                let temp = currentNode;
                while (temp.parent) {
                    path.push(temp);
                    temp = temp.parent;
                }
                path.push(start);
                return path.reverse(); // 返回从起点到终点的路径
            }

            // 从打开列表中移除当前节点，并加入关闭列表
            openList.splice(lowestIndex, 1);
            closedList.push(currentNode);

            // 获取当前节点的邻居节点
            let neighbors = dir == 'four' ? this.getNeighbors(grid, currentNode) : this.getNeighborsEight(grid, currentNode);
            // console.log('邻居节点',neighbors)
            for (let neighbor of neighbors) {
                if (closedList.find((item)=>{ return item.x==neighbor.x && item.y==neighbor.y}) || neighbor.isWall || neighbor.isWallTemp) {
                    continue; // 跳过已处理节点或障碍物
                }

                let tentative_g = currentNode.g + 1; // 从起点到邻居节点的代价
                
                
                if (!openList.find((item)=>{ return item.x==neighbor.x && item.y==neighbor.y}) ) {
                    openList.push(neighbor); // 将邻居节点加入打开列表
                } else if (tentative_g >= neighbor.g) {
                    continue; // 如果新的路径代价不低于已知路径代价，则跳过
                }

                // 更新邻居节点的代价和父节点
                neighbor.g = tentative_g;
                neighbor.h = this.heuristic(neighbor, end);
                neighbor.f = neighbor.g + neighbor.h;
                neighbor.parent = currentNode;
            }


        }
        console.log('没有找到路径');
        return [];
    }

    /**渲染路径*/
    renderPath(path: Array<MapType[0][0]>) {
        console.log(path);
        let box = this.node.getChildByName('box');
        box.children.forEach((el) => {
            if (el.name !== 'wall') el.getComponent(Sprite).color = color().fromHEX('#ffffff');
        });

        let resList = [];
        path.forEach((el, i) => {
            let index = el.y * 12 + el.x;
            //一个一个渲染
            resList.push(new Promise<void>((resolve, reject) => {
                this.scheduleOnce(() => {
                    box.children[index].getComponent(Sprite).color = color().fromHEX('#ff0000');
                    resolve();
                }, i * 0.1);
            }));

        });

        Promise.all(resList).then(() => {
            console.log('路径渲染完毕');
            this.startNode = null;
            this.endNode = null;
            this.isPath = true;
            this.isClick = false;

        });

    }

    update(deltaTime: number) {

    }
}


